package crontab

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"longmen/server/config/global"
	_const "longmen/server/pkg/common/helper/const"
	"longmen/server/pkg/common/helper/encrypt"
	"longmen/server/pkg/db/mysql/db_sports"
	"longmen/server/pkg/db/mysql/models/models_sports"
	"longmen/server/pkg/db/redis/cache"
	"mime/multipart"
	"net/http"
	"net/textproto"
	"strconv"
	"strings"

	"github.com/spf13/cast"
)

var (
	sports_nba = "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=100000&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01"
	sports_cba = "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=100008&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01"
	// sports_epl   = "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=8&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01"   // 英超
	// sports_csl   = "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=208&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01" // 中超
	// sports_liga  = "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=22&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01"  // 德甲
	// sports_slp   = "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=23&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01"  // 西甲
	// sports_isa   = "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=21&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01"  // 意甲
	// sports_ligue = "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=24&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01"  // 法甲
)

var football = map[string]string{
	"英超": "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=8&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01",
	"中超": "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=208&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01",
	"德甲": "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=22&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01",
	"西甲": "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=23&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01",
	"意甲": "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=21&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01",
	"法甲": "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=24&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01",
	"欧冠": "https://matchweb.sports.qq.com/match/api/v2/statistic/rankings?competition_id=5&season_id=&season_type=&type=0&scene=pc&qimei=e96327a1c6233bc192ec1ba303000006d18b01",
}

type Team struct {
	Code int `json:"code"`
	Data struct {
		Groups []struct {
			Tables []struct {
				Rows []struct {
					Values []struct {
						Idx   int    `json:"idx"`
						Code  string `json:"code"`
						Value struct {
							CNName string `json:"cnName"`
							Logo   string `json:"logo"`
							ID     string `json:"id"`
						} `json:"value"`
					} `json:"values"`
				} `json:"rows"`
			} `json:"tables"`
		} `json:"groups"`
	} `json:"data"`
}

type Score struct {
	Code int `json:"code"`
	Data struct {
		Groups []struct {
			Tables []struct {
				Rows []struct {
					Values []struct {
						Idx   int    `json:"idx"`
						Value string `json:"value"`
					} `json:"values"`
				} `json:"rows"`
			} `json:"tables"`
		} `json:"groups"`
	} `json:"data"`
}

func SyncPoint() {
	SyncNBAPoint()
	SyncCBAPoint()
	SyncFootballPoint()
}

func request(url string) []byte {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		fmt.Printf("sports_qq err#0: %s\n", err)
		return nil
	}

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Printf("sports_qq err#1: %s\n", err)
		return nil
	}

	body, err := io.ReadAll(res.Body)
	if err != nil {
		fmt.Printf("sports_qq err#2: %s\n", err)
		return nil
	}

	return body
}

func SyncNBAPoint() {
	var err error
	body := request(sports_nba)
	if body == nil {
		return
	}
	var nbateam Team
	var nbapoint Score

	json.Unmarshal(body, &nbateam)
	json.Unmarshal(body, &nbapoint)

	// 西部排名
	var name = "西部排名"
	if nbateam.Code == 0 {
		err = global.Sport().Model(&models_sports.BasketballPoint{}).Where("name=?", name).Delete(nil).Error
		if err != nil {
			fmt.Println(err)
		}
	}

	for idx, v := range nbateam.Data.Groups[0].Tables[0].Rows {
		var tname string
		var teamID int
		var logo string
		for i := 0; i < len(v.Values); i++ {
			tname = v.Values[1].Value.CNName
			teamID, _ = strconv.Atoi(v.Values[1].Value.ID)
			// logo = v.Values[1].Value.Logo
		}
		team, _ := db_sports.BasketballTeam(tname)
		if team.Logo != "" {
			logo = team.Logo
		}
		if len(logo) <= 0 {
			logo = fetchAndStoreLogo(name+tname, v.Values[1].Value.Logo)
		}

		rank, _ := strconv.Atoi(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[0].Value)
		win, _ := strconv.Atoi(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[2].Value)
		lost, _ := strconv.Atoi(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[3].Value)
		rate := transPercent(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[5].Value)
		streak := nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[12].Value

		log.Println("rete====>", rate)
		rateValue, _ := strconv.ParseFloat(rate, 64)
		log.Println("rete value====>", rateValue)

		var bbpoint = &models_sports.BasketballPoint{
			ID:       teamID,
			CompID:   1,
			TeamID:   teamID,
			Name:     name,
			TeamName: tname,
			Won:      win,
			Lost:     lost,
			WonRate:  rateValue,
			TeamLogo: logo,
			Scope:    5,
			Streak:   streak,
			Rank:     rank,
		}
		err = global.Sport().Model(&models_sports.BasketballPoint{}).Create(&bbpoint).Error
		if err != nil {
			fmt.Println(err)
		}

	}

	// 东部排名
	name = "东部排名"
	err = global.Sport().Model(&models_sports.BasketballPoint{}).Where("name=?", name).Delete(nil).Error
	if err != nil {
		fmt.Println(err)
	}

	for idx, v := range nbateam.Data.Groups[0].Tables[1].Rows {
		var tname string
		var teamID int
		var logo string
		for i := 0; i < len(v.Values); i++ {
			tname = v.Values[1].Value.CNName
			teamID, _ = strconv.Atoi(v.Values[1].Value.ID)
			// logo = v.Values[1].Value.Logo
		}
		team, _ := db_sports.BasketballTeam(tname)
		if team.Logo != "" {
			logo = team.Logo
		}
		if len(logo) <= 0 {
			logo = fetchAndStoreLogo(name+tname, v.Values[1].Value.Logo)
		}

		rank, _ := strconv.Atoi(nbapoint.Data.Groups[0].Tables[1].Rows[idx].Values[0].Value)
		win, _ := strconv.Atoi(nbapoint.Data.Groups[0].Tables[1].Rows[idx].Values[2].Value)
		lost, _ := strconv.Atoi(nbapoint.Data.Groups[0].Tables[1].Rows[idx].Values[3].Value)
		rate := transPercent(nbapoint.Data.Groups[0].Tables[1].Rows[idx].Values[5].Value)
		streak := nbapoint.Data.Groups[0].Tables[1].Rows[idx].Values[12].Value

		log.Println("rete====>", rate)
		rateValue, _ := strconv.ParseFloat(rate, 64)
		log.Println("rete value====>", rateValue)

		var bbpoint = &models_sports.BasketballPoint{
			ID:       teamID,
			CompID:   1,
			TeamID:   teamID,
			Name:     name,
			TeamName: tname,
			Won:      win,
			Lost:     lost,
			WonRate:  rateValue,
			TeamLogo: logo,
			Scope:    5,
			Streak:   streak,
			Rank:     rank,
		}
		err = global.Sport().Model(&models_sports.BasketballPoint{}).Create(&bbpoint).Error
		if err != nil {
			fmt.Println(err)
		}
	}
}

func SyncCBAPoint() {

	var err error
	body := request(sports_cba)
	if body == nil {
		return
	}
	var nbateam Team
	var nbapoint Score

	json.Unmarshal(body, &nbateam)
	json.Unmarshal(body, &nbapoint)

	// CBA积分榜
	var name = "CBA积分榜"
	if nbateam.Code == 0 {
		err = global.Sport().Model(&models_sports.BasketballPoint{}).Where("comp_id=?", 3).Delete(nil).Error
		if err != nil {
			fmt.Println(err)
		}
	}

	for idx, v := range nbateam.Data.Groups[0].Tables[0].Rows {
		var tname string
		var teamID int
		var logo string
		for i := 0; i < len(v.Values); i++ {
			tname = v.Values[1].Value.CNName
			teamID, _ = strconv.Atoi(v.Values[1].Value.ID)
			//logo = v.Values[1].Value.Logo
		}

		team, _ := db_sports.BasketballTeam(tname)
		if team.Logo != "" {
			logo = team.Logo
		}
		if len(logo) <= 0 {
			logo = fetchAndStoreLogo(name+tname, v.Values[1].Value.Logo)
		}

		rank, _ := strconv.Atoi(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[0].Value)
		win, _ := strconv.Atoi(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[2].Value)
		lost, _ := strconv.Atoi(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[3].Value)
		rate := transPercent(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[5].Value)

		log.Println("rete====>", rate)
		rateValue, _ := strconv.ParseFloat(rate, 64)
		log.Println("rete value====>", rateValue)

		var bbpoint = &models_sports.BasketballPoint{
			ID:       teamID,
			CompID:   3,
			TeamID:   teamID,
			Name:     name,
			TeamName: tname,
			Won:      win,
			Lost:     lost,
			WonRate:  rateValue,
			TeamLogo: logo,
			Scope:    5,
			Rank:     rank,
		}
		err = global.Sport().Model(&models_sports.BasketballPoint{}).Create(&bbpoint).Error
		if err != nil {
			fmt.Println(err)
		}

	}
}

func SyncFootballPoint() {
	for idx, v := range football {
		var err error
		body := request(v)
		if body == nil {
			return
		}
		var nbateam Team
		var nbapoint Score

		json.Unmarshal(body, &nbateam)
		json.Unmarshal(body, &nbapoint)

		// {Id: 82, Name: "英超"},
		// {Id: 120, Name: "西甲"},
		// {Id: 129, Name: "德甲"},
		// {Id: 108, Name: "意甲"},
		// {Id: 142, Name: "法甲"},
		// {Id: 542, Name: "中超"},
		// {Id: 46, Name: "欧冠"},
		// {Id: 45, Name: "欧洲杯"},
		var compID int
		if idx == "英超" {
			compID = 82
		}
		if idx == "西甲" {
			compID = 120
		}
		if idx == "德甲" {
			compID = 129
		}
		if idx == "意甲" {
			compID = 108
		}
		if idx == "法甲" {
			compID = 142
		}
		if idx == "中超" {
			compID = 542
		}
		if idx == "欧冠" {
			compID = 46
		}
		if nbateam.Code == 0 {
			err = global.Sport().Model(&models_sports.FootballPoint{}).Where("comp_id=?", compID).Delete(nil).Error
			if err != nil {
				fmt.Println(err)
			}
		}

		for idx, v := range nbateam.Data.Groups[0].Tables[0].Rows {
			var tname string
			var teamID int
			var logo string
			for i := 0; i < len(v.Values); i++ {
				tname = v.Values[1].Value.CNName
				teamID, _ = strconv.Atoi(v.Values[1].Value.ID)
				//logo = v.Values[1].Value.Logo
			}
			team, _ := db_sports.FootballTeam(tname)
			if team.Logo != "" {
				logo = team.Logo
			}
			if len(logo) <= 0 {
				logo = fetchAndStoreLogo(fmt.Sprintf("%d%s", compID, tname), v.Values[1].Value.Logo)
			}

			var win, draw, loss, rank int

			point, _ := strconv.Atoi(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[5].Value)

			if compID == 142 { // 法甲结构不一
				rank, _ = strconv.Atoi(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[0].Value)
				point, _ = strconv.Atoi(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[2].Value)
				win, _ = strconv.Atoi(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[4].Value)
				draw, _ = strconv.Atoi(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[5].Value)
				loss, _ = strconv.Atoi(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[6].Value)
			} else {
				data := strings.Split(nbapoint.Data.Groups[0].Tables[0].Rows[idx].Values[3].Value, "/")
				win, _ = strconv.Atoi(data[0])
				draw, _ = strconv.Atoi(data[1])
				loss, _ = strconv.Atoi(data[2])
			}

			var bbpoint = &models_sports.FootballPoint{
				ID:       teamID,
				CompID:   compID,
				TeamID:   teamID,
				TeamName: tname,
				Won:      win,
				Loss:     loss,
				Draw:     draw,
				Points:   point,
				TeamLogo: logo,
				Rank:     rank,
			}
			err = global.Sport().Model(&models_sports.FootballPoint{}).Create(&bbpoint).Error
			if err != nil {
				fmt.Println(err)
			}

		}
	}
}

func transPercent(rate string) string {
	rate = strings.Trim(rate, "%")
	rateF := float64(int(cast.ToFloat64(rate)*10)) / 1000.0
	return fmt.Sprintf("%.3f", rateF)
}

func fetchAndStoreLogo(teamName, logoUrl string) string {
	configPub := cache.GetConfigPub()
	if len(configPub.ThirdUpload) <= 0 {
		return logoUrl
	}
	newLogoUrl := global.GetRds().HGet(_const.FetchUrlSaveHash, teamName).Val()
	if len(newLogoUrl) > 0 {
		return newLogoUrl
	}
	imageData, contentType, err := fetchImage(logoUrl)
	if err != nil {
		global.Log.Errorf("fetchImage error: %+v", err)
		return logoUrl
	}

	newLogoUrl, err = uploadImageToSelfService(imageData, configPub.ThirdUpload, contentType, encrypt.Md5(teamName))
	if err != nil {
		global.Log.Errorf("uploadImageerror: %+v", err)
		return logoUrl
	}
	global.GetRds().HSet(_const.FetchUrlSaveHash, teamName, newLogoUrl)
	return newLogoUrl
}

func fetchImage(imageURL string) ([]byte, string, error) {
	resp, err := http.Get(imageURL)
	if err != nil {
		return nil, "", fmt.Errorf("failed to download image: %v", err)
	}
	defer resp.Body.Close()

	imageData, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, "", fmt.Errorf("failed to read image data: %v", err)
	}

	return imageData, resp.Header.Get("Content-Type"), nil
}

func uploadImageToSelfService(imageData []byte, uploadApiHost, contentType, teamName string) (string, error) {
	var buf bytes.Buffer
	writer := multipart.NewWriter(&buf)

	h := make(textproto.MIMEHeader)
	h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file"; filename="%s"`, teamName))
	h.Set("Content-Type", contentType)

	part, err := writer.CreatePart(h)
	if err != nil {
		return "", fmt.Errorf("failed to create form part: %v", err)
	}

	_, err = part.Write(imageData)
	if err != nil {
		return "", fmt.Errorf("failed to write image data: %v", err)
	}

	err = writer.Close()
	if err != nil {
		return "", fmt.Errorf("failed to close writer: %v", err)
	}

	req, err := http.NewRequest("POST", uploadApiHost, &buf)
	if err != nil {
		return "", fmt.Errorf("failed to create request: %v", err)
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", fmt.Errorf("failed to send request: %v", err)
	}
	defer resp.Body.Close()

	responseData, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("failed to read response: %v", err)
	}

	result := struct {
		Status int    `json:"status"`
		Data   string `json:"data"`
		Msg    string `json:"msg"`
		ErrMsg string `json:"err_msg"`
	}{}
	json.Unmarshal(responseData, &result)
	if result.Status != 0 {
		return "", fmt.Errorf("failed to upload : %v", result)
	}

	urls := strings.Split(result.Data, ",")
	if len(urls) <= 0 {
		return "", fmt.Errorf("unexpected response format")
	}
	return urls[0], nil
}
